<?php
/**
 * @author all@cosmos-framework.org
 * @copyright (c) 2013 cosmos-framework.org
 * @license http://www.opensource.org/licenses/mit-license.php
 * @link http://cosmos-framework.org/
 * @package cosmos.framework
 * @version 2.0
 */
namespace Cosmos;

class Component {

    private $_component;
    private $_componentArgs;
    private $_ref;

    /**
     * @param mixed $component
     * @param mixed $componentArgs
     */
    public function __construct($component, $componentArgs = array()) {

        $this->_component = function() use ($componentArgs) {

            static $_;
            return $_ ? : $_ = call_user_func($this->_ref)->newInstanceArgs($componentArgs);
        };

        $this->_ref = function() use ($component) {

            static $_;
            return $_ ? : $_ = new \ReflectionClass($component);
        };
    }

    /**
     * @param string $methodName
     * @param mixed[] $methodArgs
     * @return mixed
     */
    public function __call($methodName, $methodArgs) {

        static $_;
        if (!$f = &$_[$methodName]) {
            $component = $this->_component;
            if ($comments = $this->methodComments($methodName)) {
                foreach (self::annos($comments) as $c => $componentArgs) {
                    $component = function() use ($c, $component, $componentArgs) {
                        return new $c($component(), $componentArgs, $this->_ref);
                    };
                }
            }

            $f = array($component(), $methodName);
        }

        // invoke response.
        return call_user_func_array($f, $methodArgs);
    }

    /**
     * @param string $methodName
     * @return string[]
     */
    protected static function annos($comments) {

        $response = array();
        if (self::_match($comments, $p)) {
            foreach ($p as $anno) {
                $response[$anno[1]] = isset($anno[2]) ? str_getcsv($anno[2]) : array();
            }
        }
        // response [].
        return $response;
    }

    /**
     * @param string $methodName
     * @return string
     */
    protected function methodComments($methodName) {

        return call_user_func($this->_ref)->getMethod($methodName)->getDocComment();
    }

    /**
     * @access private
     */
    private static function _match($comments, &$p) {

        return preg_match_all('/@(\\\\[a-zA-Z_\x7f-\xff][\\\\\w]*)(?: (.*))?/', $comments, $p, PREG_SET_ORDER);
    }

}
